/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using DaveSexton.DocProject.Resources;

namespace DaveSexton.DocProject.Engine
{
	internal sealed class InternalCreateDocSiteContentsStep : BuildStep<IBuildEngine>
	{
		#region Public Properties
		public override string Name
		{
			get
			{
				return "Generate Table of Contents for DocSite";
			}
		}
		#endregion

		#region Private / Protected
		private readonly HelpSystem help;
		private volatile bool canceled;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="InternalCreateDocSiteContentsStep" /> class.
		/// </summary>
		public InternalCreateDocSiteContentsStep(HelpSystem helpSystem, IBuildEngine engine)
			: base(engine)
		{
			if (helpSystem == null)
				throw new ArgumentNullException("helpSystem");

			help = helpSystem;

			RunInBackground = true;
		}
		#endregion

		#region Methods
		protected override void ExecuteInternal(BuildContext context)
		{
			if (canceled)
			{
				// reset private canceled field in case the step is reused
				canceled = false;
				return;
			}

			string tocFile = Engine.Settings.DocSiteTargetContentsXmlFile;
			string path = Path.GetDirectoryName(tocFile);

			if (!Directory.Exists(path))
				Directory.CreateDirectory(path);

			context.TraceLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.Text.CreatingDocSiteToc, tocFile));

			context.Engine.Project.GetItem(tocFile).Checkout();

			using (FileStream stream = new FileStream(tocFile, FileMode.Create, FileAccess.Write))
			{
				WriteDocSiteContentsXmlFile(help.Topics, stream);
			}
		}

		protected override void CancelInternal(BuildContext context)
		{
			canceled = true;
		}

		private void WriteDocSiteContentsXmlFile(IEnumerable<HelpItem> topics, Stream stream)
		{
			/* Sample: 
			<?xml version="1.0" encoding="utf-8" ?>
			<topics>
				<topic name="WindowsApplication1 Namespace" file="help/html/N_WindowsApplication1.htm">
					<topic name="Form1 Class" file="help/html/T_WindowsApplication1_Form1.htm">
						<topic name="Form1 Constructor " file="help/html/C_WindowsApplication1_Form1_ctor.htm" />
						<topic name="Dispose Method (disposing)" file="help/html/M_WindowsApplication1_Form1_Dispose_1_36d384f7.htm" />
					</topic>
				</topic>
			</topics>
			*/

			XmlWriterSettings writerSettings = new XmlWriterSettings();
			writerSettings.Indent = true;

			using (XmlWriter writer = XmlWriter.Create(stream, writerSettings))
			{
				writer.WriteStartDocument();
				writer.WriteStartElement("topics");

				WriteDocSiteContentsXmlRecursive(topics, writer);

				writer.WriteEndElement();
				writer.WriteEndDocument();
			}
		}

		private void WriteDocSiteContentsXmlRecursive(IEnumerable<HelpItem> topics, XmlWriter writer)
		{
			foreach (HelpItem topic in topics)
			{
				if (canceled)
				{
					// reset private canceled field in case the step is reused
					canceled = false;
					return;

					// NOTE: All of the end elements will still be written since this operation is recursive, 
					// so the xml document should still be valid, although it will be missing information.
				}

				writer.WriteStartElement("topic");
				writer.WriteAttributeString("name", topic.Name);

				if (topic.File != null)
					writer.WriteAttributeString("file", topic.File);

				IEnumerable<HelpItem> subItems = topic.Subitems;

				if (subItems != null)
					WriteDocSiteContentsXmlRecursive(subItems, writer);

				writer.WriteEndElement();
			}
		}

		public override string ToString()
		{
			return "Creates the " + Engine.Settings.DocSiteContentsXmlFileName + " file.";
		}
		#endregion
	}
}
